{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true,
    "ExecuteTime": {
     "end_time": "2023-12-11T02:30:04.074686300Z",
     "start_time": "2023-12-11T02:30:01.022205400Z"
    }
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 准备数据"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [
    {
     "data": {
      "text/plain": "   customerID  gender  SeniorCitizen Partner Dependents  tenure PhoneService  \\\n0  7590-VHVEG  Female              0     Yes         No       1           No   \n1  5575-GNVDE    Male              0      No         No      34          Yes   \n2  3668-QPYBK    Male              0      No         No       2          Yes   \n3  7795-CFOCW    Male              0      No         No      45           No   \n4  9237-HQITU  Female              0      No         No       2          Yes   \n\n      MultipleLines InternetService OnlineSecurity  ... DeviceProtection  \\\n0  No phone service             DSL             No  ...               No   \n1                No             DSL            Yes  ...              Yes   \n2                No             DSL            Yes  ...               No   \n3  No phone service             DSL            Yes  ...              Yes   \n4                No     Fiber optic             No  ...               No   \n\n  TechSupport StreamingTV StreamingMovies        Contract PaperlessBilling  \\\n0          No          No              No  Month-to-month              Yes   \n1          No          No              No        One year               No   \n2          No          No              No  Month-to-month              Yes   \n3         Yes          No              No        One year               No   \n4          No          No              No  Month-to-month              Yes   \n\n               PaymentMethod MonthlyCharges  TotalCharges Churn  \n0           Electronic check          29.85         29.85    No  \n1               Mailed check          56.95        1889.5    No  \n2               Mailed check          53.85        108.15   Yes  \n3  Bank transfer (automatic)          42.30       1840.75    No  \n4           Electronic check          70.70        151.65   Yes  \n\n[5 rows x 21 columns]",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>customerID</th>\n      <th>gender</th>\n      <th>SeniorCitizen</th>\n      <th>Partner</th>\n      <th>Dependents</th>\n      <th>tenure</th>\n      <th>PhoneService</th>\n      <th>MultipleLines</th>\n      <th>InternetService</th>\n      <th>OnlineSecurity</th>\n      <th>...</th>\n      <th>DeviceProtection</th>\n      <th>TechSupport</th>\n      <th>StreamingTV</th>\n      <th>StreamingMovies</th>\n      <th>Contract</th>\n      <th>PaperlessBilling</th>\n      <th>PaymentMethod</th>\n      <th>MonthlyCharges</th>\n      <th>TotalCharges</th>\n      <th>Churn</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>7590-VHVEG</td>\n      <td>Female</td>\n      <td>0</td>\n      <td>Yes</td>\n      <td>No</td>\n      <td>1</td>\n      <td>No</td>\n      <td>No phone service</td>\n      <td>DSL</td>\n      <td>No</td>\n      <td>...</td>\n      <td>No</td>\n      <td>No</td>\n      <td>No</td>\n      <td>No</td>\n      <td>Month-to-month</td>\n      <td>Yes</td>\n      <td>Electronic check</td>\n      <td>29.85</td>\n      <td>29.85</td>\n      <td>No</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>5575-GNVDE</td>\n      <td>Male</td>\n      <td>0</td>\n      <td>No</td>\n      <td>No</td>\n      <td>34</td>\n      <td>Yes</td>\n      <td>No</td>\n      <td>DSL</td>\n      <td>Yes</td>\n      <td>...</td>\n      <td>Yes</td>\n      <td>No</td>\n      <td>No</td>\n      <td>No</td>\n      <td>One year</td>\n      <td>No</td>\n      <td>Mailed check</td>\n      <td>56.95</td>\n      <td>1889.5</td>\n      <td>No</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>3668-QPYBK</td>\n      <td>Male</td>\n      <td>0</td>\n      <td>No</td>\n      <td>No</td>\n      <td>2</td>\n      <td>Yes</td>\n      <td>No</td>\n      <td>DSL</td>\n      <td>Yes</td>\n      <td>...</td>\n      <td>No</td>\n      <td>No</td>\n      <td>No</td>\n      <td>No</td>\n      <td>Month-to-month</td>\n      <td>Yes</td>\n      <td>Mailed check</td>\n      <td>53.85</td>\n      <td>108.15</td>\n      <td>Yes</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>7795-CFOCW</td>\n      <td>Male</td>\n      <td>0</td>\n      <td>No</td>\n      <td>No</td>\n      <td>45</td>\n      <td>No</td>\n      <td>No phone service</td>\n      <td>DSL</td>\n      <td>Yes</td>\n      <td>...</td>\n      <td>Yes</td>\n      <td>Yes</td>\n      <td>No</td>\n      <td>No</td>\n      <td>One year</td>\n      <td>No</td>\n      <td>Bank transfer (automatic)</td>\n      <td>42.30</td>\n      <td>1840.75</td>\n      <td>No</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>9237-HQITU</td>\n      <td>Female</td>\n      <td>0</td>\n      <td>No</td>\n      <td>No</td>\n      <td>2</td>\n      <td>Yes</td>\n      <td>No</td>\n      <td>Fiber optic</td>\n      <td>No</td>\n      <td>...</td>\n      <td>No</td>\n      <td>No</td>\n      <td>No</td>\n      <td>No</td>\n      <td>Month-to-month</td>\n      <td>Yes</td>\n      <td>Electronic check</td>\n      <td>70.70</td>\n      <td>151.65</td>\n      <td>Yes</td>\n    </tr>\n  </tbody>\n</table>\n<p>5 rows × 21 columns</p>\n</div>"
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.read_csv(\"F:/机器学习数据集/电信客户流失数据/WA_Fn-UseC_-Telco-Customer-Churn.csv\")\n",
    "df.head()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T02:31:46.792833700Z",
     "start_time": "2023-12-11T02:31:46.151837100Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [
    {
     "data": {
      "text/plain": "   customerid  gender  seniorcitizen partner dependents  tenure phoneservice  \\\n0  7590-vhveg  female              0     yes         no       1           no   \n1  5575-gnvde    male              0      no         no      34          yes   \n2  3668-qpybk    male              0      no         no       2          yes   \n3  7795-cfocw    male              0      no         no      45           no   \n4  9237-hqitu  female              0      no         no       2          yes   \n\n      multiplelines internetservice onlinesecurity  ... deviceprotection  \\\n0  no_phone_service             dsl             no  ...               no   \n1                no             dsl            yes  ...              yes   \n2                no             dsl            yes  ...               no   \n3  no_phone_service             dsl            yes  ...              yes   \n4                no     fiber_optic             no  ...               no   \n\n  techsupport streamingtv streamingmovies        contract paperlessbilling  \\\n0          no          no              no  month-to-month              yes   \n1          no          no              no        one_year               no   \n2          no          no              no  month-to-month              yes   \n3         yes          no              no        one_year               no   \n4          no          no              no  month-to-month              yes   \n\n               paymentmethod monthlycharges  totalcharges churn  \n0           electronic_check          29.85         29.85    no  \n1               mailed_check          56.95        1889.5    no  \n2               mailed_check          53.85        108.15   yes  \n3  bank_transfer_(automatic)          42.30       1840.75    no  \n4           electronic_check          70.70        151.65   yes  \n\n[5 rows x 21 columns]",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>customerid</th>\n      <th>gender</th>\n      <th>seniorcitizen</th>\n      <th>partner</th>\n      <th>dependents</th>\n      <th>tenure</th>\n      <th>phoneservice</th>\n      <th>multiplelines</th>\n      <th>internetservice</th>\n      <th>onlinesecurity</th>\n      <th>...</th>\n      <th>deviceprotection</th>\n      <th>techsupport</th>\n      <th>streamingtv</th>\n      <th>streamingmovies</th>\n      <th>contract</th>\n      <th>paperlessbilling</th>\n      <th>paymentmethod</th>\n      <th>monthlycharges</th>\n      <th>totalcharges</th>\n      <th>churn</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>7590-vhveg</td>\n      <td>female</td>\n      <td>0</td>\n      <td>yes</td>\n      <td>no</td>\n      <td>1</td>\n      <td>no</td>\n      <td>no_phone_service</td>\n      <td>dsl</td>\n      <td>no</td>\n      <td>...</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>month-to-month</td>\n      <td>yes</td>\n      <td>electronic_check</td>\n      <td>29.85</td>\n      <td>29.85</td>\n      <td>no</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>5575-gnvde</td>\n      <td>male</td>\n      <td>0</td>\n      <td>no</td>\n      <td>no</td>\n      <td>34</td>\n      <td>yes</td>\n      <td>no</td>\n      <td>dsl</td>\n      <td>yes</td>\n      <td>...</td>\n      <td>yes</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>one_year</td>\n      <td>no</td>\n      <td>mailed_check</td>\n      <td>56.95</td>\n      <td>1889.5</td>\n      <td>no</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>3668-qpybk</td>\n      <td>male</td>\n      <td>0</td>\n      <td>no</td>\n      <td>no</td>\n      <td>2</td>\n      <td>yes</td>\n      <td>no</td>\n      <td>dsl</td>\n      <td>yes</td>\n      <td>...</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>month-to-month</td>\n      <td>yes</td>\n      <td>mailed_check</td>\n      <td>53.85</td>\n      <td>108.15</td>\n      <td>yes</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>7795-cfocw</td>\n      <td>male</td>\n      <td>0</td>\n      <td>no</td>\n      <td>no</td>\n      <td>45</td>\n      <td>no</td>\n      <td>no_phone_service</td>\n      <td>dsl</td>\n      <td>yes</td>\n      <td>...</td>\n      <td>yes</td>\n      <td>yes</td>\n      <td>no</td>\n      <td>no</td>\n      <td>one_year</td>\n      <td>no</td>\n      <td>bank_transfer_(automatic)</td>\n      <td>42.30</td>\n      <td>1840.75</td>\n      <td>no</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>9237-hqitu</td>\n      <td>female</td>\n      <td>0</td>\n      <td>no</td>\n      <td>no</td>\n      <td>2</td>\n      <td>yes</td>\n      <td>no</td>\n      <td>fiber_optic</td>\n      <td>no</td>\n      <td>...</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>month-to-month</td>\n      <td>yes</td>\n      <td>electronic_check</td>\n      <td>70.70</td>\n      <td>151.65</td>\n      <td>yes</td>\n    </tr>\n  </tbody>\n</table>\n<p>5 rows × 21 columns</p>\n</div>"
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.columns = df.columns.str.lower().str.replace(\" \",\"_\")\n",
    "str_cols = list(df.dtypes[df.dtypes=='object'].index)\n",
    "for col in str_cols:\n",
    "    df[col] = df[col].str.lower().str.replace(\" \",\"_\")\n",
    "df.head()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T02:38:27.514168300Z",
     "start_time": "2023-12-11T02:38:27.305172200Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "outputs": [
    {
     "data": {
      "text/plain": "   customerid  gender  seniorcitizen partner dependents  tenure phoneservice  \\\n0  7590-vhveg  female              0     yes         no       1           no   \n1  5575-gnvde    male              0      no         no      34          yes   \n2  3668-qpybk    male              0      no         no       2          yes   \n3  7795-cfocw    male              0      no         no      45           no   \n4  9237-hqitu  female              0      no         no       2          yes   \n\n      multiplelines internetservice onlinesecurity  ... deviceprotection  \\\n0  no_phone_service             dsl             no  ...               no   \n1                no             dsl            yes  ...              yes   \n2                no             dsl            yes  ...               no   \n3  no_phone_service             dsl            yes  ...              yes   \n4                no     fiber_optic             no  ...               no   \n\n  techsupport streamingtv streamingmovies        contract paperlessbilling  \\\n0          no          no              no  month-to-month              yes   \n1          no          no              no        one_year               no   \n2          no          no              no  month-to-month              yes   \n3         yes          no              no        one_year               no   \n4          no          no              no  month-to-month              yes   \n\n               paymentmethod monthlycharges  totalcharges churn  \n0           electronic_check          29.85         29.85     0  \n1               mailed_check          56.95        1889.5     0  \n2               mailed_check          53.85        108.15     1  \n3  bank_transfer_(automatic)          42.30       1840.75     0  \n4           electronic_check          70.70        151.65     1  \n\n[5 rows x 21 columns]",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>customerid</th>\n      <th>gender</th>\n      <th>seniorcitizen</th>\n      <th>partner</th>\n      <th>dependents</th>\n      <th>tenure</th>\n      <th>phoneservice</th>\n      <th>multiplelines</th>\n      <th>internetservice</th>\n      <th>onlinesecurity</th>\n      <th>...</th>\n      <th>deviceprotection</th>\n      <th>techsupport</th>\n      <th>streamingtv</th>\n      <th>streamingmovies</th>\n      <th>contract</th>\n      <th>paperlessbilling</th>\n      <th>paymentmethod</th>\n      <th>monthlycharges</th>\n      <th>totalcharges</th>\n      <th>churn</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>7590-vhveg</td>\n      <td>female</td>\n      <td>0</td>\n      <td>yes</td>\n      <td>no</td>\n      <td>1</td>\n      <td>no</td>\n      <td>no_phone_service</td>\n      <td>dsl</td>\n      <td>no</td>\n      <td>...</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>month-to-month</td>\n      <td>yes</td>\n      <td>electronic_check</td>\n      <td>29.85</td>\n      <td>29.85</td>\n      <td>0</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>5575-gnvde</td>\n      <td>male</td>\n      <td>0</td>\n      <td>no</td>\n      <td>no</td>\n      <td>34</td>\n      <td>yes</td>\n      <td>no</td>\n      <td>dsl</td>\n      <td>yes</td>\n      <td>...</td>\n      <td>yes</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>one_year</td>\n      <td>no</td>\n      <td>mailed_check</td>\n      <td>56.95</td>\n      <td>1889.5</td>\n      <td>0</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>3668-qpybk</td>\n      <td>male</td>\n      <td>0</td>\n      <td>no</td>\n      <td>no</td>\n      <td>2</td>\n      <td>yes</td>\n      <td>no</td>\n      <td>dsl</td>\n      <td>yes</td>\n      <td>...</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>month-to-month</td>\n      <td>yes</td>\n      <td>mailed_check</td>\n      <td>53.85</td>\n      <td>108.15</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>7795-cfocw</td>\n      <td>male</td>\n      <td>0</td>\n      <td>no</td>\n      <td>no</td>\n      <td>45</td>\n      <td>no</td>\n      <td>no_phone_service</td>\n      <td>dsl</td>\n      <td>yes</td>\n      <td>...</td>\n      <td>yes</td>\n      <td>yes</td>\n      <td>no</td>\n      <td>no</td>\n      <td>one_year</td>\n      <td>no</td>\n      <td>bank_transfer_(automatic)</td>\n      <td>42.30</td>\n      <td>1840.75</td>\n      <td>0</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>9237-hqitu</td>\n      <td>female</td>\n      <td>0</td>\n      <td>no</td>\n      <td>no</td>\n      <td>2</td>\n      <td>yes</td>\n      <td>no</td>\n      <td>fiber_optic</td>\n      <td>no</td>\n      <td>...</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>no</td>\n      <td>month-to-month</td>\n      <td>yes</td>\n      <td>electronic_check</td>\n      <td>70.70</td>\n      <td>151.65</td>\n      <td>1</td>\n    </tr>\n  </tbody>\n</table>\n<p>5 rows × 21 columns</p>\n</div>"
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.churn = (df.churn=='yes').astype(int)\n",
    "df.head()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T02:39:15.470519500Z",
     "start_time": "2023-12-11T02:39:15.378485700Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "outputs": [
    {
     "data": {
      "text/plain": "customerid           object\ngender               object\nseniorcitizen         int64\npartner              object\ndependents           object\ntenure                int64\nphoneservice         object\nmultiplelines        object\ninternetservice      object\nonlinesecurity       object\nonlinebackup         object\ndeviceprotection     object\ntechsupport          object\nstreamingtv          object\nstreamingmovies      object\ncontract             object\npaperlessbilling     object\npaymentmethod        object\nmonthlycharges      float64\ntotalcharges         object\nchurn                 int32\ndtype: object"
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.dtypes"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T02:39:52.674334400Z",
     "start_time": "2023-12-11T02:39:52.644328400Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "outputs": [
    {
     "data": {
      "text/plain": "dtype('float64')"
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.totalcharges = pd.to_numeric(df.totalcharges,errors='coerce')\n",
    "df.totalcharges.dtypes"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T02:42:11.037816700Z",
     "start_time": "2023-12-11T02:42:11.002823Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "outputs": [
    {
     "data": {
      "text/plain": "customerid           0\ngender               0\nseniorcitizen        0\npartner              0\ndependents           0\ntenure               0\nphoneservice         0\nmultiplelines        0\ninternetservice      0\nonlinesecurity       0\nonlinebackup         0\ndeviceprotection     0\ntechsupport          0\nstreamingtv          0\nstreamingmovies      0\ncontract             0\npaperlessbilling     0\npaymentmethod        0\nmonthlycharges       0\ntotalcharges        11\nchurn                0\ndtype: int64"
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.isnull().sum()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T02:42:27.453320600Z",
     "start_time": "2023-12-11T02:42:27.398280700Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "outputs": [
    {
     "data": {
      "text/plain": "customerid          0\ngender              0\nseniorcitizen       0\npartner             0\ndependents          0\ntenure              0\nphoneservice        0\nmultiplelines       0\ninternetservice     0\nonlinesecurity      0\nonlinebackup        0\ndeviceprotection    0\ntechsupport         0\nstreamingtv         0\nstreamingmovies     0\ncontract            0\npaperlessbilling    0\npaymentmethod       0\nmonthlycharges      0\ntotalcharges        0\nchurn               0\ndtype: int64"
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.totalcharges=df.totalcharges.fillna(0)\n",
    "df.isnull().sum()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T02:43:14.870611600Z",
     "start_time": "2023-12-11T02:43:14.849587800Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 划分数据集"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "outputs": [
    {
     "data": {
      "text/plain": "(5634, 1409)"
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "df_train_full,df_test = train_test_split(df,test_size=0.2,random_state=11)\n",
    "len(df_train_full),len(df_test)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T02:55:57.440933100Z",
     "start_time": "2023-12-11T02:55:57.395918700Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 编写训练函数"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "outputs": [],
   "source": [
    "categorical = ['gender','seniorcitizen','partner','dependents','phoneservice','multiplelines'\n",
    "               ,'internetservice','onlinesecurity','onlinebackup','deviceprotection','techsupport',\n",
    "               'streamingtv','streamingmovies','contract','paperlessbilling','paymentmethod']\n",
    "numerical = ['tenure','monthlycharges','totalcharges']"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T02:46:44.618509400Z",
     "start_time": "2023-12-11T02:46:44.599473700Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "outputs": [],
   "source": [
    "from sklearn.feature_extraction import DictVectorizer\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "def train(df,y,C):\n",
    "    cat = df[categorical+numerical].to_dict(orient='records') # 将数据转化为字典\n",
    "    dv = DictVectorizer(sparse=False)\n",
    "    dv.fit(cat)\n",
    "    X = dv.transform(cat)\n",
    "    model = LogisticRegression(C=C,solver='liblinear')\n",
    "    model.fit(X,y)\n",
    "    return dv,model"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T02:50:52.597885800Z",
     "start_time": "2023-12-11T02:50:51.429480800Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 定义预测函数"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "outputs": [],
   "source": [
    "def predict(df,dv,model):\n",
    "    cat = df[categorical+numerical].to_dict(orient='records')\n",
    "    X = dv.transform(cat) # 使用与训练中相同的独热编码方案\n",
    "    y_pred=model.predict_proba(X)[:,1] # 使用该模型进行预测\n",
    "    return y_pred"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T02:54:02.826153700Z",
     "start_time": "2023-12-11T02:54:02.807188100Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "C=0.001, auc均值:0.823, auc标准差:0.015\n",
      "C=0.01, auc均值:0.840, auc标准差:0.012\n",
      "C=0.1, auc均值:0.844, auc标准差:0.012\n",
      "C=0.5, auc均值:0.844, auc标准差:0.012\n",
      "C=1, auc均值:0.844, auc标准差:0.012\n",
      "C=10, auc均值:0.844, auc标准差:0.012\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import KFold\n",
    "from sklearn.metrics import roc_auc_score\n",
    "nfolds = 5\n",
    "kfold = KFold(n_splits=nfolds,random_state=1,shuffle=True) # 将数据转化为10个部分\n",
    "for C in [0.001,0.01,0.1,0.5,1,10]:\n",
    "    aucs = []\n",
    "    for train_idx,val_idx in kfold.split(df_train_full):\n",
    "        df_train =df_train_full.iloc[train_idx]\n",
    "        df_val = df_train_full.iloc[val_idx]\n",
    "\n",
    "        y_train = df_train.churn.values\n",
    "        y_val = df_val.churn.values\n",
    "\n",
    "        dv,model = train(df_train,y_train,C=C)\n",
    "        y_pred = predict(df_val,dv,model)\n",
    "        auc = roc_auc_score(y_val,y_pred)\n",
    "        aucs.append(auc)\n",
    "    print(\"C={}, auc均值:{:.3f}, auc标准差:{:.3f}\".format(C,np.mean(aucs),np.std(aucs)))"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T03:07:47.283360700Z",
     "start_time": "2023-12-11T03:07:39.238371200Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 利用C=0.1与训练集的所有数据重新训练模型"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "auc=0.852\n"
     ]
    }
   ],
   "source": [
    "y_train =df_train_full.churn.values\n",
    "y_test = df_test.churn.values\n",
    "\n",
    "dv,model = train(df_train_full[categorical+numerical],y_train,C)# 在完整的数据集上训练数据\n",
    "y_pred = predict(df_test,dv,model) # 将模型应用于测试集\n",
    "auc = roc_auc_score(y_test,y_pred)\n",
    "print('auc={:.3f}'.format(auc))"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T03:58:28.232136600Z",
     "start_time": "2023-12-11T03:58:27.733138700Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "outputs": [
    {
     "data": {
      "text/plain": "{'gender': 'female',\n 'seniorcitizen': 0,\n 'partner': 'yes',\n 'dependents': 'no',\n 'phoneservice': 'no',\n 'multiplelines': 'no_phone_service',\n 'internetservice': 'dsl',\n 'onlinesecurity': 'yes',\n 'onlinebackup': 'no',\n 'deviceprotection': 'no',\n 'techsupport': 'no',\n 'streamingtv': 'no',\n 'streamingmovies': 'no',\n 'contract': 'month-to-month',\n 'paperlessbilling': 'yes',\n 'paymentmethod': 'electronic_check',\n 'tenure': 4,\n 'monthlycharges': 29.05,\n 'totalcharges': 129.6}"
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "customer = df_test[categorical+numerical].iloc[2]\n",
    "customer=customer.to_dict()\n",
    "customer"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T04:18:22.904552900Z",
     "start_time": "2023-12-11T04:18:22.884554100Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "outputs": [
    {
     "data": {
      "text/plain": "0.5629469055153569"
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.DataFrame([customer])\n",
    "y_pred = predict(df,dv,model)\n",
    "y_pred[0]"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T04:18:23.683382600Z",
     "start_time": "2023-12-11T04:18:23.674378100Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "outputs": [
    {
     "data": {
      "text/plain": "customerid                3398-fshon\ngender                        female\nseniorcitizen                      1\npartner                           no\ndependents                        no\ntenure                            12\nphoneservice                     yes\nmultiplelines                    yes\ninternetservice          fiber_optic\nonlinesecurity                    no\nonlinebackup                     yes\ndeviceprotection                  no\ntechsupport                       no\nstreamingtv                      yes\nstreamingmovies                   no\ncontract              month-to-month\npaperlessbilling                 yes\npaymentmethod       electronic_check\nmonthlycharges                  91.3\ntotalcharges                  1094.5\nchurn                              1\nName: 6625, dtype: object"
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_test.iloc[0]"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T04:18:26.491171500Z",
     "start_time": "2023-12-11T04:18:26.475135700Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "outputs": [],
   "source": [
    "## 预测单个客户\n",
    "def predict_single(customer,dv,model): # 不传递一个DataFrame,而是一个客户\n",
    "    X = dv.transform([customer])\n",
    "    y_pred=model.predict_proba(X)[:,1]\n",
    "    return  y_pred"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T04:25:48.148223900Z",
     "start_time": "2023-12-11T04:25:48.120221100Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "outputs": [
    {
     "data": {
      "text/plain": "array([0.56294691])"
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "predict_single(customer,dv,model)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T04:26:25.322539Z",
     "start_time": "2023-12-11T04:26:25.293501200Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 使用pickle保存模型"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 保存模型,加载模型"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "outputs": [],
   "source": [
    "import pickle\n",
    "with open('churn-model.bin','wb') as f_out:# 指定要保存的文件\n",
    "    pickle.dump((dv,model),f_out) # 用pickle保存文件"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T04:31:38.899432100Z",
     "start_time": "2023-12-11T04:31:38.870429100Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 加载模型"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "outputs": [],
   "source": [
    "with open('churn-model.bin','rb') as f_in:\n",
    "    dv,model = pickle.load(f_in) # 加载元组并解包它"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T04:35:34.941135Z",
     "start_time": "2023-12-11T04:35:34.892173500Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "outputs": [
    {
     "data": {
      "text/plain": "array([0.56294691])"
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "predict_single(customer,dv,model)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T04:36:13.739261400Z",
     "start_time": "2023-12-11T04:36:13.683259500Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 发送请求"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'churn': False, 'churn_probability': 0.056527019935897836}\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "customer={\n",
    "    'gender':'female','seniorcitizen':0,'partner':'no','dependents':'no','phoneservice':'yes',\n",
    "    'multiplelines':'no',\n",
    "    'internetservice':'dsl','onlinesecurity':'yes','onlinebackup':'no','deviceprotection':'yes','techsupport':'yes',\n",
    "    'streamingtv':'yes','streamingmovies':'yes','contract':'one_year','paperlessbilling':'yes','paymentmethod':'bank_transfer_(automatic)',\n",
    "    'tenure':41,'monthlycharges':79.85,'totalcharges':3320.75\n",
    "}\n",
    "url ='http://127.0.0.1:9696/predict'\n",
    "response = requests.post(url,json=customer)# 在post请求中发送客户\n",
    "result = response.json() #将结果解析为json格式\n",
    "print(result)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-12-11T06:00:17.277948300Z",
     "start_time": "2023-12-11T06:00:17.107323400Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
